package IceAssembly;

/**
 *  <html>
 *    <head>
 *      
 *    </head>
 *    <body>
 *      <p style="margin-top: 0">
 * Instruction processor that makes decisions based on the instruction being a 
 * pseudo-op or a regular instruction, and performs checks and other 
 * considerations to ensure that labels, parameters, and operations and 
 * functions are all correct and can be added to the tables for the assembly 
 * of the pass1 intermediate file to be used further in the program.
 *      </p>
 *    </body>
 *  </html>
 */
public class Process {
    Table table_instance = new Table();
    Check check_instance = new Check();
    SubProcess sub_process_instance = new SubProcess();
    Initialize init_instance = new Initialize();
    Convert convert_instance = new Convert();
    
    /**
     * Determines whether the instruction was a mnemonic instruction, or a 
     * directive/pseudo-op and then takes makes the appropriate action to have 
     * those processed accordingly.
     * <p>
     * <b>Change Log:</b><br>
     * April 14 - Documented function - Peter<br>
     * April 16 - Changed role to be controller for mnemonics and directives and 
     * implemented function - Peter<br>
     * <p>
     * <b>Error Conditions Tested:</b><br>
     * 100 - Invalid instruction, substituting MOPER ADD,0<br>
     * 200 - Invalid label <br>
     * <p>
     * <b>Error Messages Generated:</b><br>
     * <INSERT EACH ERROR MESSAGE GENERATED> <br>
     * <p>
     * <b>Date of module being installed:</b> 4/14/08
     * @author Peter Dietz
     * @param tokened_string String array that has code, label, mnem, func, param
     */
    public int processInstruction (String[] tokened_string){
        /*  Tokened_string[]
         *  Index 0 : code - 0/1 - (0-no label, 1-label)
         *  Index 1 : label if any
         *  Index 2 : Mnemonic or directive
         *  Index 3 : function or (function or operands)
         *  Index 4 : comma if any
         *  Index 5 : operands for mnemonic if any
         */
        if (tokened_string[0].contentEquals("1")){//contains a label.            
            if (check_instance.isValidLabel(tokened_string[1])==0){//Invalid syntactically or pre defined
                if(table_instance.addToErrorTable("104")==0){
                    return 1000;//fatal error more than 3072 errors.
                }
                tokened_string[0]="0";
            }
            if (check_instance.isValidLabel(tokened_string[1])==2){//in symbol table
                if(table_instance.addToErrorTable("205")==0){
                    return 1000;//fatal error more than 3072 errors.
                }
                tokened_string[0]="0";
            }
        }
        if(Control.line_num == 0 || tokened_string[2].toUpperCase().compareTo("START")==0){
            return sub_process_instance.processStart(tokened_string);            
        }
          
        if(check_instance.isMnemonic(tokened_string[2]) == 1){
            return processMnemonic(tokened_string);
        }else if(check_instance.isPseudoOP(tokened_string[2]) == 1){
            return processPseudoOp(tokened_string);
        }else{//substitute moper add,0
            if(table_instance.addToErrorTable("100")==0){
                return 1000;//fatal error more than 3072 errors.
            }
            if(table_instance.addToIntermediateFile("11000", "00000000000", "A") == 0){
                return 2000;//fatal error more than 1024 memory words.
            }
            Control.location_counter++;
            return 50;
        }
    }

    /**
     * Processes the mnemonic instruction by checking that it is valid, and 
     * finds the binary code for the instruction-function pairing. Also the 
     * label required will be checked and the parameters will be checked that 
     * they are correct. Additionally, the instruction is added to the 
     * intermediate file, symbol table, and error table if neccessary.
     * <p>
     * <b>Change Log:</b><br>
     * April 16 - Added operation and documented it - Peter<br>
     * April 18 - changed how we receive info with getInfoForMnemonic - Peter<br>
     * <p>
     * <b>Error Conditions Tested:</b><br>
     * 101 - Mnemonic and function pair not found, substitute MOPER ADD,0<br>
     * <p>
     * <b>Date of module being installed:</b> April 16
     * @author Peter Dietz
     * @param tokened_string String array that has code, label, mnem, func, param
     * @return success of operation. 1 is success, 0 is fail
     */    
    public int processMnemonic (String[] tokened_string) {        
        String[] info = init_instance.getInfoForMnemonicPair(tokened_string[2], tokened_string[3]);
        /* info[]
         * Index 0 - code - 0/1 - (0-pair not found and 1-pair found)
         * Index 1 - binary - 5bits
         * Index 2 - operands 0/1/2/3 - (0=none, 1=rlabel, 2=nn, 3=binary_label)
         * Index 3 - relocation possibilities - a, r, e, c
        */
        if(info[0].contentEquals("0")){
            // 101 - Mnemonic and function pair not found, substituting MOPER ADD,0
            if(table_instance.addToErrorTable("101")==0){
                return 1000;//fatal error - more than 3072 errors.
            }
            if(table_instance.addToIntermediateFile("11000", "00000000000", "A") == 0){
                return 2000;//fatal error - more than 1024 memory words.
            }
            Control.location_counter++;
            return 50;//proceed to next line
        }
        if(tokened_string[0].contentEquals("1")){
            if(table_instance.addToSymbolTable(tokened_string[1], "label", "-")==0){
                if(table_instance.addToErrorTable("112")==0){
                    return 1000;
                }
            }
        }
        int status = processMnemonicParameter(info[1], info[2], tokened_string[4], tokened_string[5]);
        if(status==50){            
            Control.location_counter++;
        }
        return status;
    }
    
    /**
     * Processes pseudo-op from assembly code does validation for errors in the 
     * label and operands. Fetches the binary code for instructions if needed. 
     * Adds labels or other directives to the symbol table, and determines if
     * the instruction consumed memory, and increments the location_counter. 
     * Lastly it adds the instruction to the intermediate_file or error_table if
     * neccessary.
     * <p>
     * Change Log:<br>
     * April 14 - Documented function - Peter<br>
     * April 16 - Changed return type to string array - Peter<br>
     * <p>
     * Error Conditions Tested:<br>
     * <INSERT EACH CONDITION TESTED> <br>
     * <p>
     * Error Messages Generated: <br>
     * <INSERT EACH ERROR MESSAGE GENERATED> <br>
     * <p>
     * Date of module being installed: 4/14/08
     * @param tokened_string String array that has code, label, mnem, func, param
     * @return The success of the operation. 1 is success, and 0 is failure
     */        
    public int processPseudoOp (String[] tokened_string) {                
        String[] info = init_instance.getInfoForPseudoOp(tokened_string[2]);
        /* info[]
         * Index 0 = code - 0/1
         * Index 1 = length
         * Index 2 = operand format
         * Index 3 = label_number (0,1,2) not number of labels
        */        
        if(tokened_string[2].toUpperCase().compareTo("END")==0){
            return sub_process_instance.processEnd(tokened_string);            
        }
        if(info[3].compareTo("0")==0){
            if(tokened_string[0].compareTo("0")==0){//no label found when required                
                table_instance.addToErrorTable("107");
            }
        }
        if(info[3].compareTo("2")==0){
            if(tokened_string[0].compareTo("0")==1){//found a label when not required
                table_instance.addToErrorTable("108");
                
            }            
        }                
        if(tokened_string[4].compareTo(",")==0){//found a comma in pseudo-op
            table_instance.addToErrorTable("203");            
        }
        
        int is_valid_operand = processPseudoOpParameters(info[2],tokened_string[3]);
        if(is_valid_operand==0){//Not Valid Operands
            table_instance.addToErrorTable("XXX");
            //error code - XXX - not valid operands
        }
        return 0;//don't know the use of this return statement
    }
   
    /**
     * This function process the Pseudo-Op Parameters, checks for error and add them to error table.<br>
     * <p>
     * <b>Change Log:</b><br>
     * <DATE> <REASON - WHAT YOU DID> <USER> <br>
     * <p>
     * <b>Error Conditions Tested:</b><br>
     * <INSERT EACH CONDITION TESTED> <br>
     * <p>
     * <b>Error Messages Generated:</b><br>
     * <INSERT EACH ERROR MESSAGE GENERATED> <br>
     * <p>
     * <b>Date of module being installed:</b> <INSERT DATE HERE>
     * @param parameter_info - Contains the type of parameter
     * @param parameter - Contains the parameter
     * @return int : to be added
     */
    private int processPseudoOpParameters(String parameter_info, String parameter){
        /*
        if(parameter_info.compareTo("")==0){//means no operands...
            
        }
        if(parameter_info.compareTo("nn")==0){
            if(sub_process_instance.processAlln(parameter_info,parameter)==2){
                
            }else{
                table_instance.addToErrorTable("150"); 
            }            
        }else if(parameter_info.compareTo("nmax")==0){
            if(sub_process_instance.processAlln(parameter_info,parameter)==2){
                
            }else{
                table_instance.addToErrorTable("151");
            }
        }else if(parameter_info.compareTo("Mlabel")==0){            
        }else if(parameter_info.compareTo("nmax or elabel")==0){            
        }else if(parameter_info.compareTo("rlabel")==0){
        }else if(parameter_info.compareTo("option")==0){
            if(parameter.toUpperCase().compareTo("ON")==0){
            }else if(parameter.toUpperCase().compareTo("OFF")==0){
            }else{
                table_instance.addToErrorTable("152");
            }
        }else if(parameter_info.compareTo("program_name")==0){            
        }else if(parameter_info.compareTo("S=")==0){
            if(sub_process_instance.processLiterals(parameter)==1){
                
            }else{
                
            }
        }else if(parameter_info.compareTo("FORMULA")==0){
        }*/
        return 0;
    }
    
    /**
     * Checks that the parameter is valid for the parameter type, including checks 
     * that it is of the valid range for that type. Additionally this operation 
     * shall try to determine the relocation_type if it can by eliminating choices
     * that would be invalid. Adds to error table if it found errors, and corrects
     * parameters to a default value if they were incorrect for their type.
     * <p>
     * Change Log:<br>
     * April 14 - Documented function - Peter<br>
     * April 18 - Changed parameters to help with mnemonics and pseudo-ops - Peter
     * <p>
     * Error Conditions Tested:<br>
     * 102 - expected parameters, but none were present<br>
     * 103 - Operand not in valid range for rlabel<br>
     * 104 - not a valid label syntactically<br>
     * 105 - Operand was not in valid range for nn<br>
     * 106 - Operand was not in valid range for binary label<br>
     * 201 - expected no parameters, but received parameters<br>
     * 202 - Instruction required comma for seperator character<br>
     * 203 - Instruction required no seperator character<br>
     * <p>
     * Date of module being installed: April 14
     * @author Peter Dietz
     * @param parameter_info information representing type of parameter
     * @param op_code The machine operation code to be processed
     * @param separator Seperation character between operation-function and operand
     * @param parameter Parameters to the instruction or psuedo-op
     * @return Processing parameters completed successfully 1, 0 if error in parameters
     */    
    public int processMnemonicParameter(String op_code, String parameter_info, String separator, String parameter){
        //take care of no operands mnemonics.
        if(parameter_info.contentEquals("none")){
            if(separator.compareTo(",")==0){
                if(table_instance.addToErrorTable("201")==0){
                    return 1000;//fatal error more than 3072 errors.
                }           
            }    
            if(table_instance.addToIntermediateFile(op_code, "00000000000", "A") == 0){//cntl halt
                return 2000;//fatal error more than 1024 memory words.                
            }
            return 50;            
        }
        //takes care of separator character.
        if(!separator.contentEquals(",")){
            if(table_instance.addToErrorTable("113")==0){
                return 1000;//fatal error more than 3072 errors.
            }
            if(table_instance.addToIntermediateFile("11000", "00000000000", "A") == 0){
                return 2000;//fatal error more than 1024 memory words.                
            }
            return 50;
        }        
        if(parameter_info.contentEquals("binary5")){
            String temp_value = sub_process_instance.processBinary5(parameter);
            if(temp_value.contentEquals("0")){
                if(table_instance.addToErrorTable("106")==0){
                    return 1000;//fatal error more than 3072 errors.
                }
                if(table_instance.addToIntermediateFile("11000", "00000000000", "A") == 0){//moper add,0
                    return 2000;//fatal error more than 1024 memory words
                }
                return 50;
            }else{
                if(table_instance.addToIntermediateFile(op_code, "0"+temp_value, "A") == 0){//moper add,0
                    return 2000;//fatal error more than 1024 memory words
                }
                return 50;
            }
        }else if(parameter_info.contentEquals("binary4")){
            String temp_value = sub_process_instance.processBinary4(parameter);
            if(temp_value.contentEquals("0")){
                if(table_instance.addToErrorTable("114")==0){
                    return 1000;//fatal error more than 3072 errors.
                }
                if(table_instance.addToIntermediateFile("11000", "00000000000", "A") == 0){//moper add,0
                    return 2000;//fatal error more than 1024 memory words
                }
                return 50;
            }else{
                if(table_instance.addToIntermediateFile(op_code, "0"+temp_value, "A") == 0){//moper add,0
                    return 2000;//fatal error more than 1024 memory words
                }
                return 50;
            }
        }else if(parameter_info.contentEquals("nn")){
            int temp_value = sub_process_instance.processAlln(parameter_info, parameter);
            if(temp_value!=2){//not in range or a string
                if(table_instance.addToErrorTable("105")==0){
                    return 1000;//fatal error more than 3072 errors.
                }
                if(table_instance.addToIntermediateFile("11000", "00000000000", "A") == 0){
                   return 2000;//fatal error more than 1024 memory words.                
                }
                return 50;
            }else{//in range
                if(table_instance.addToIntermediateFile(op_code,"0"+convert_instance.getBitCode(parameter,10), "A") == 0){
                   return 2000;//fatal error more than 1024 memory words.                
                }
                return 50;
            }
        }else if(parameter_info.contentEquals("rlabel")){
            String try1 = sub_process_instance.check_1(parameter);
            if(try1.compareTo("1000")==0 || try1.compareTo("2000")==0 || try1.compareTo("50")==0){
                return Integer.parseInt(try1);
            }
            if(try1.compareTo("0")!=0){
                if(table_instance.addToIntermediateFile(op_code,try1, "A") == 0){
                   return 2000;//fatal error more than 1024 memory words.                
                }
                return 50;
            }
            
            String try2 = sub_process_instance.check_2(parameter);
            if(try2.compareTo("1000")==0 || try2.compareTo("2000")==0 || try2.compareTo("50")==0){
                return Integer.parseInt(try2);
            }
            if(try2.compareTo("0")!=0){
                if(table_instance.addToIntermediateFile(op_code,try2, "A") == 0){
                   return 2000;//fatal error more than 1024 memory words.                
                }
                return 50;
            }
            
            String try3 = sub_process_instance.check_3(parameter);
            if(try3.compareTo("1000")==0 || try3.compareTo("2000")==0 || try3.compareTo("50")==0){
                return Integer.parseInt(try3);
            }
            if(try3.compareTo("0")!=0){
                if(table_instance.addToIntermediateFile(op_code,try3, "A") == 0){
                   return 2000;//fatal error more than 1024 memory words.                
                }
                return 50;
            }
            
        }else if(parameter_info.contentEquals("memoryaddress")){
            String try1 = sub_process_instance.check_1(parameter);
            if(try1.compareTo("1000")==0 || try1.compareTo("2000")==0 || try1.compareTo("50")==0){
                return Integer.parseInt(try1);
            }
            if(try1.compareTo("0")!=0){
                if(table_instance.addToIntermediateFile(op_code,try1, "A") == 0){
                   return 2000;//fatal error more than 1024 memory words.                
                }
                return 50;
            }
            
            String try3 = sub_process_instance.check_3(parameter);
            if(try3.compareTo("1000")==0 || try3.compareTo("2000")==0 || try3.compareTo("50")==0){
                return Integer.parseInt(try3);
            }
            if(try3.compareTo("0")!=0){
                if(table_instance.addToIntermediateFile(op_code,try3, "A") == 0){
                   return 2000;//fatal error more than 1024 memory words.                
                }
                return 50;
            }
        }
        else{
            System.out.println("You are fucking mad there is no such type");
        }
        
        return 0;
    }
}

        /*
        // tracks if an error has been found
        int error_free = 1;
        int operand_code = -1;
        //Check validity of operands. 0->none, 1->rlabel, 2->nn, 3->binary_label
        if(parameter_type.contentEquals("none")){
            operand_code = 0;
        } else if(parameter_type.contentEquals("rlabel")){
            operand_code = 1;
        } else if(parameter_type.contentEquals("nn")){
            operand_code = 2;
        } else if(parameter_type.contentEquals("binary")){
            operand_code = 3;
        }
        
        
        
        //Check seperators make sense
        if(operand_code == 0){
            //none operand
             if(! parameter_seperator.contentEquals("")){
                // 203 - Instruction required no seperator character
                table_instance.addToErrorTable("203");
                parameter_seperator = "";
            }
        } else {
            if(! parameter_seperator.contentEquals(",")){
                // 202 - Instruction required comma for seperator character
                table_instance.addToErrorTable("202");
            }
        }
        
        //Check parameters make sense
        switch(operand_code){
            case 0:
                //none operand
                if(parameter_string.length() != 0){
                    // 201 - expected no parameters, but parameters were present. --ignored 
                    table_instance.addToErrorTable("201");
                    parameter_string = "";
                }
                break;
            case 1:
                //rlabel
                if(parameter_string.length() == 0){
                    //102 - expected parameters, but none were present
                    table_instance.addToErrorTable("102");
                    error_free = 0;
                }
                int is_number =1;
                try {
                    Integer.valueOf(parameter_string);
                } catch (NumberFormatException exception) {
                    is_number = 0;
                }
                if(is_number == 1){
                    if(check_instance.isParameterOverflow(parameter_string, "nmax") == 1){
                        // 103 - Operand not in valid range for rlabel
                        table_instance.addToErrorTable("103");
                        error_free=0;
                    }
                    parameter_string = Integer.toBinaryString(Integer.valueOf(parameter_string, 2));
                } else {
                    //had to be a word label
                    if(check_instance.isValidLabel(parameter_string) == 0){
                        // 104 - not a valid label syntactically
                        table_instance.addToErrorTable("104");
                        error_free = 0;
                    }
                }
                break;
            case 2:
                //nn
                if (check_instance.isParameterOverflow(parameter_string, parameter_type) ==1){
                    // 105 - Operand was not in valid range for nn
                    table_instance.addToErrorTable("105");
                    error_free=0;
                }
                parameter_string = Integer.toBinaryString(Integer.valueOf(parameter_string, 2));
                break;
            case 3:
                //binary label
                if (check_instance.isParameterOverflow(parameter_string, parameter_type) ==1){
                    // 106 - Operand was not in valid range for binary label
                    table_instance.addToErrorTable("106");
                    error_free=0;
                }
                break;
        }
        return error_free;
    */       

